import re

class Operators(object):
    class Base(object):
        def className(self):
            return self.__class__.__name__
            
        def _check_values(self, *values):
            result = list()
            for vl in values:
                if (vl == None):
                    vl = ''
                result.append(vl)
            
            return tuple(result)
                
    
    class Regex(Base):
        def __init__(self, *flags):
            self._flags = flags
            
        def check(self, pattern, itemValue):
            (pattern, itemValue) = self._check_values(pattern, itemValue)
            
            if (not self._re_search(pattern, itemValue)):
                return False
                
            return True
        
        def _re_search(self, pattern, itemValue):
            search  = None
            if (len(self._flags) > 0):
                flags = map(lambda f: str(f), self._flags)
                search = re.search(str(pattern), str(itemValue), eval("|".join(flags)))
            else:
                search = re.search(str(pattern), str(itemValue))
            
            return search

    class Equal(Regex):
        def check(self, value, itemValue):
            (value, itemValue) = self._check_values(value, itemValue)
            
            return Operators.Regex.check(self, "^%s$" % (value), itemValue)
            
    class NotEqual(Regex):
        def check(self, value, itemValue):
            (value, itemValue) = self._check_values(value, itemValue)
            
            if (not self._re_search("^%s$" % (value), itemValue)):
                return True
                
            return False
            
    class In(Regex):
        def check(self, values, itemValue):
            (itemValue) = self._check_values(itemValue)
            
            if (not isinstance(values, list)):
                values = list()
            
            #convert the list of objects, to list of object strings
            for idx in range(0, len(values)):
                values[idx] = str(values[idx])
            ###############
            
            return Operators.Regex.check(self, "^(%s)$" % ('|'.join(values)), itemValue)
    
    class GreaterLowerBase(Base):
        def __init__(self, ignorecase=True):
            self._ignorecase = ignorecase
        
        def _check_ignorecase(self, *values):
            result = values
            
            if (self._ignorecase):
                result = list()
                for value in values:
                    result.append(str(value).lower())
                
            return tuple(result)
    
    class GreaterThan(GreaterLowerBase):
        def check(self, value, itemValue):
            (value, itemValue) = self._check_values(value, itemValue)
            (value, itemValue) = self._check_ignorecase(value, itemValue)
            if (itemValue <= value):
                return False
            
            return True
            
    class GreaterOrEqualThan(GreaterLowerBase):
         def check(self, value, itemValue):
             (value, itemValue) = self._check_values(value, itemValue)
             (value, itemValue) = self._check_ignorecase(value, itemValue)
             if (itemValue < value):
                 return False
            
             return True
            
    class LowerThan(GreaterLowerBase):
        def check(self, value, itemValue):
            (value, itemValue) = self._check_values(value, itemValue)
            (value, itemValue) = self._check_ignorecase(value, itemValue)
            if (itemValue >= value):
                return False
            
            return True
            
    class LowerOrEqualThan(GreaterLowerBase):
         def check(self, value, itemValue):
             (value, itemValue) = self._check_values(value, itemValue)
             (value, itemValue) = self._check_ignorecase(value, itemValue)
             if (itemValue > value):
                 return False
            
             return True
    
    class Between(GreaterLowerBase):
        def check(self, start, end, itemValue):
            (start, end, itemValue) = self._check_values(start, end, itemValue)
            (start, end, itemValue) = self._check_ignorecase(start, end, itemValue)
            if (itemValue >= start and itemValue <= end):
                return True
            
            return False

class Clause(object):
    def __init__(self, column, operator, **kwargs):
        self._operator = operator
        self._column = column
        self._params = {} #list of the parameters for the operator
        
        if (isinstance(operator, Operators.Between)): #if between, need start and end
            self._params = {'start': {}, 'end': {}}
        elif (isinstance(operator, Operators.In)): #need an array of values
            self._params = {'values': {'type': list}}
        else:
            self._params = {'value': {}}
        
        #check if we received the parameters
        received_params = kwargs.keys()
        for param in self._params.keys():
            if (not param in received_params):
                raise AttributeError("attribute %s is missing" % (param))
            elif 'type' in self._params[param].keys(): #check if the param is from the expected type
                if (not isinstance(kwargs[param], self._params[param]['type'])):
                    raise AttributeError("attribute %s must be of type %s" % (param, str(param['type'])))
                
            self._params[param]['value'] = kwargs[param]
    
    @property
    def Column(self):
        return self._column
    
    def validate(self, itemValue):
        if (isinstance(self._operator, Operators.Between)):
            return self._operator.check(self._params['start']['value'], self._params['end']['value'], itemValue)
        elif (isinstance(self._operator, Operators.In)):
            return self._operator.check(self._params['values']['value'], itemValue)
        else:
            return self._operator.check(self._params['value']['value'], itemValue)
    
    def __repr__(self):
        return "Operator: %s\n Column: %s\n Value(s): %s" % (self._operator.className(), self.Column, self._params)

class ListSearch(object):
    def __call__(self, clauses, listObjects):
        finalList = []
        
        if (not isinstance(listObjects, list)):
            raise AttributeError("expecting a list for parameter 'listObject'")
        
        for item in listObjects:
            if (self._check_item(clauses, item, 1)): #if the item is valid, add it to finalList
                finalList.append(item)
                
        return finalList
    
    def _check_item(self, clauses, item, level):
        #odd levels -> and
        #pair levels -> or
        
        valid = True
        
        for clause in clauses:
            validClause = False
            
            if (isinstance(clause, list)):
                validClause = self._check_item(clause, item, level + 1)
            else:
                if (not isinstance(clause, Clause)): #check if the clause is based on the Clause class
                    raise AttributeError("Invalid clause: " + str(clause))
                
                if (hasattr(item, clause.Column)):
                    validClause = clause.validate(getattr(item, clause.Column))
                elif (item.has_key(clause.Column)): #for dictionary items
                    validClause = clause.validate(item[clause.Column])
                    
            #check if is an OR or AND
            if ((level % 2) == 0): #or
                if (not validClause):
                    valid = False
                else:
                    valid = True
                    break #on OR only needs one valid clause
            else: #and
                if (not validClause):
                    valid = False
                    break #on AND we need that all clauses are valid
        
        return valid 

if (__name__ == '__main__'):
    l = ListSearch()
    print(l([Clause('name', Operators.Equal(), value=None), 
             [Clause('nam', Operators.NotEqual(re.I), value='andr'), Clause('nam', Operators.Equal(re.I), value='Andrr')]], 
             [{'name': None, 'nam': 'andrr'}, {'name': None, 'nam': 'andr'}]))